home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / pasfoss1.zip / AMFOSSIL.PAS < prev    next >
Pascal/Delphi Source File  |  1991-04-18  |  28KB  |  688 lines

  1. {$D-}  { Debug Information Off }
  2. { $S-}  { Stack Checking Off    }
  3. {$V-}  { String Checking Off   }
  4.  
  5. Unit AMFOSSIL;
  6. { Copyright (C) 1990 Andrew J. Mead
  7.   All Rights Reserved.
  8.  
  9.   Contact:
  10.       POB 1155 Chapel Hill NC 27514-1155 USA
  11.       1:151/223 (Andrew J. Mead) Fido Net
  12.       98@9968 WWIV Net
  13.   }
  14.  
  15. { original version written 4/18/91
  16.  
  17.   AM FOSSIL is FREEWARE.  You may distribute it and use it as you will.
  18.   Only distribute it in complete form.  If you use the routines, please
  19.   give credit.
  20.  
  21.   Portions of these routines are used in the BBS Onliner Interface (BOI).
  22.   Both Pascal and C source code versions are available from Andrew Mead.
  23.   The BBS Onliner Interface allows programmers to easily write online
  24.   doors that run under more than 30 different BBS systems, with or
  25.   without FOSSIL installed, using standard or non-standard IRQ/port
  26.   address combinations, or even using locked bps modems.  The BOI is
  27.   a SHAREWARE product.  Look for BOI???C.ZIP or BOI???P.ZIP where
  28.   ??? represents the current version number.
  29. }
  30.  
  31. { Important Notice :
  32.     Most of the documentation provided with each Function and Procedure was
  33.     derived (plagerized) from{
  34.                  Fundamentals of FOSSIL implementation and use
  35.                         Version 5,  February 11,  1988
  36.                        Rick Moore,  Solar Wind Computing
  37.                           FidoNet Address:  1:115/333
  38.                  FidoNet Standards Committee index:  FSC-0015
  39.  Copyright (C) 1988, Rick Moore,  Homewood,  IL, 60430. All rights reserved.
  40.  
  41.  I urge you to read this document (FSC-0015.DOC) and its companion
  42.  (FSC-0015.CHT) before using and FOSSIL routines.  This document in either
  43.  arc or zip format should be available on any FidoNet BBS near you.
  44. }
  45.  
  46. INTERFACE
  47.  
  48. Const
  49. { These constants only for use with SetContCK, see procedure for more details }
  50.   ckenable  = $01;  { enable ctrl-c/ctrl-k interception }
  51.   ckdisable = $00;  { disable ctrl-c/ctrl-k interception }
  52.   transtop  = $02;  { halt transmission }
  53.   transclr  = $00;  { resume transmission }
  54.  
  55. Type
  56.   fossinforec = record         { for use with Procedure DriverInfo }
  57.       info_size     : word;    { size of the structure in bytes      }
  58.       curr_fossil   : byte;    { FOSSIL spec driver conforms to      }
  59.       curr_rev      : byte;    { rev level of this specific driver   }
  60.       id_string     : pointer; { "FAR" pointer to ASCIIZ ID string   }
  61.       ibsize        : word;    { size of the input buffer (bytes)    }
  62.       ifree         : word;    { number of bytes left in buffer      }
  63.       obsize        : word;    { size of the output buffer (bytes)   }
  64.       ofree         : word;    { number of bytes left in the buffer  }
  65.       screen_width  : byte;    { width of screen on this adapter     }
  66.       screen_height : byte;    { height of screen    "     "         }
  67.       baudmask      : byte     { ACTUAL baud rate, computer to modem }
  68.     end;
  69.  
  70. Var
  71.   fport    : byte;  { FOSSIL serial port.  0 = Com1, 1 = Com2, etc. }
  72.   fresult  : word;  { FOSSIL status variable, returned by several Procedures }
  73.   fossrev  : byte;  { FOSSIL revision number }
  74.   fossfunc : byte;  { highest FOSSIL function supported }
  75.  
  76. Procedure SETBAUDRATE(mask : byte);{ $00 }  { Set modem variables }
  77. Procedure SENDFCHAR(fchar : char); { $01 }  { Transmit char with wait }
  78. Procedure READFCHAR(fchar : char); { $02 }  { Recieve char with wait }
  79. Procedure GETFSTATUS;              { $03 }  { Request FOSSIL Status }
  80. Function  INITFOSSIL : boolean;    { $04 }  { Initializes FOSSIL }
  81. Procedure DEINITFOSSIL;            { $05 }  { Terminates FOSSIL }
  82. Procedure DROPFCARRIER;            { $06 }  { Disable modem }
  83. Procedure TIMERINFO(var tickint,   { $07 }  { Get Timer Interrupt Info }
  84.     tickpersec : byte;var msecpertick : word);
  85. Procedure FLUSHOUTPUT;             { $08 }  { Flushes Output Buffer }
  86. Procedure PURGEOUTPUT;             { $09 }  { Purges Output Buffer }
  87. Procedure PURGEINPUT;              { $0A }  { Purges Input Buffer }
  88. Procedure SENDFNOW(fchar : char;   { $0B }  { Send char without wait }
  89.     var success : boolean);
  90. Procedure PEAKFCHAR(fchar : char;  { $0C }  { Non-destructive input read }
  91.     var success : boolean);
  92. Procedure READKNOW(var key : word; { $0D }  { Read keyboard without wait }
  93.     var success : boolean);
  94. Procedure READKBD(var key : word); { $0E }  { Read keyboard with wait }
  95. Procedure SETFLOWCONTROL           { $0F }  { Enable/Disable Flow Control }
  96.     (mask : byte);
  97. Procedure SETCONTCK(mask : byte;   { $10 }  { Control C/K checking }
  98.     var ckstate : boolean);
  99. Procedure SETCURSOR(row,           { $11 }  { Position cursor on screen }
  100.     column : byte);
  101. Procedure GETCURSOR(var row,       { $12 }  { Get cursor location }
  102.     column : byte);
  103. Procedure ANSICHAR(fchar : char);  { $13 }  { Write character to screen }
  104. Procedure SETWATCHDOG              { $14 }  { enable/disable WatchDog }
  105.     (enable : boolean);
  106. Procedure BIOSCHAR(fchar : char);  { $15 }  { Write character with BIOS }
  107. Procedure SETTICKFUNC              { $16 }  { Timer Interrupt Handler }
  108.     (faddr : pointer;putin : boolean;var success : boolean);
  109. Procedure COLDBOOT;                { $17 }  { Perform "cold" boot }
  110. Procedure WARMBOOT;                { $17 }  { Perform "warm" boot }
  111. Procedure READFBLOCK               { $18 }  { Read block from input buffer }
  112.     (buffaddr : pointer; numtoread : word;var numread : word);
  113. Procedure WRITEFBLOCK              { $19 }  { Write block to output buffer }
  114.     (buffaddr : pointer; numtosend : word;var numsent : word);
  115. Procedure SETBREAKSIGNAL           { $1A }  { Start/Stop break signal }
  116.     (startbreak : boolean);
  117. Procedure DRIVERINFO               { $1B }  { Get FOSSIL information }
  118.     (buffaddr : pointer; numtoread : word; var numread : word);
  119.  
  120. { These three functions call GetStatus $03 }
  121. Function  FCARRIER : boolean;               { Carrier Detect }
  122. Function  INPUTREADY : boolean;             { Input Buffer not empty }
  123. Function  OUTPUTREADY : boolean;            { Output Buffer not empty }
  124.  
  125. IMPLEMENTATION
  126.  
  127. Uses
  128.   dos;               { for the registers type }
  129.  
  130. Const
  131.   lowerdtr = $00;
  132.  
  133. Type
  134.   ptrmask = record   { segment:offset mask for address pointers }
  135.       poff : word;
  136.       pseg : word
  137.     end;
  138.  
  139. Var
  140.   regs : registers;
  141.  
  142. Procedure SETBAUDRATE(mask : byte);
  143. { See extended notes after end. of Unit
  144. }
  145.   begin {* SetBaudRate *}
  146.     regs.ah := $00;
  147.     regs.al := mask;
  148.     regs.dx := fport;
  149.     Intr($14,regs);
  150.     fresult := regs.ax    { returns FOSSIL status word }
  151.   end;  {* SetBaudRate *}
  152.  
  153. Procedure SENDFCHAR(fchar : char);
  154. { AL contains the character to be sent.   If there is room in the transmit
  155.   buffer the return will be immediate,  otherwise it will wait until there
  156.   is room to store the character in the transmit buffer.  On return, AX is
  157.   set as in a status request.
  158. }
  159.   begin {* SendFChar *}
  160.     regs.ah := $01;
  161.     regs.al := ord(fchar);
  162.     regs.dx := fport;
  163.     Intr($14,regs);
  164.     fresult := regs.ax
  165.   end;  {* SendFChar *}
  166.  
  167. Procedure READFCHAR(fchar : char);
  168. { If there is a character  available in the  receive buffer,  returns with
  169.   the next character in AL.  It will wait until a character is received if
  170.   none is available.
  171. }
  172.   begin {* ReadFChar *}
  173.     regs.ah := $02;
  174.     regs.dx := fport;
  175.     Intr($14,regs);
  176.     move(regs.al,fchar,1)
  177.   end;  {* ReadFChar *}
  178.  
  179. Procedure GETFSTATUS;
  180. { Returns with the line and modem status in AX.  Status bits returned are:
  181.             In AH:
  182.                 Bit 0 = RDA  - input data is available in buffer
  183.                 Bit 1 = OVRN - the input buffer has been overrun.  All
  184.                                characters received after the buffer is
  185.                                full should be discarded.
  186.                 Bit 5 = THRE - room is available in output buffer
  187.                 Bit 6 = TSRE - output buffer is empty
  188.             In AL:
  189.                 Bit 3 = Always 1 (always return with this bit set to 1)
  190.                 Bit 7 = DCD  - carrier detect
  191.     This can be used by the application to determine  whether carrier detect
  192.     (CD) is set,  signifying the presence/absence of a remote connection, as
  193.     well as monitoring both the input and output buffer status.  Bit 3 of AL
  194.     is always returned set to enable programs to use it as a carrier detect
  195.     bit on hardwired (null modem) links.
  196. }
  197.   begin {* GetFStatus *}
  198.     regs.ah := $03;
  199.     regs.dx := fport;
  200.     Intr($14,regs);
  201.     fresult := regs.ax
  202.   end;  {* GetFStatus *}
  203.  
  204. Function INITFOSSIL : boolean;
  205. { This is used to tell the driver to begin  operations,  and to check that
  206.   the driver is installed. This function should be called before any other
  207.   communications calls are made.  DTR is raised by this call.  The baud
  208.   rate must NOT be changed by this call.
  209.   NOTE: Should an additional call to this service occur  (2 Inits or Init,
  210.   Read,Init, etc.) the driver should reset all buffers, flow control, etc.
  211.   to the INIT state and return SUCCESS.
  212. }
  213.   begin {* fInitFOSSIL *}
  214.     regs.ah := $04;
  215.     regs.dx := fport;
  216.     Intr($14,regs);
  217.     InitFOSSIL := regs.ax = $1954;
  218.     fossrev  := regs.bh;           { FOSSIL version implemented }
  219.     fossfunc := regs.bl            { highest FOSSIL function supported }
  220.   end;  {* fInitFOSSIL *}
  221.  
  222. Procedure DEINITFOSSIL;
  223. { This is used to tell the driver that comm port operations are ended. The
  224.   function should be called  when no more comm port functions will be used
  225.   on the port specified in DX.  DTR is NOT affected by this call.
  226. }
  227.   begin {* DeinitFOSSIL *}
  228.     regs.ah := $05;
  229.     regs.dx := fport;
  230.     Intr($14,regs);
  231.   end;  {* DeinitFOSSIL *}
  232.  
  233. Procedure DROPFCARRIER;
  234. { This function is used to control the DTR line to the modem.
  235.   AL = 00h means lower DTR (disable the modem), and AL = 01h means to raise
  236.   DTR (enable the modem).  This procedure only lowers DTR.
  237. }
  238.   begin {* DropFCarrier *}
  239.     regs.ah := $06;
  240.     regs.al := lowerdtr;
  241.     regs.dx := fport;
  242.     Intr($14,regs);
  243.   end;  {* DropFCarrier *}
  244.  
  245. Procedure TIMERINFO(var tickint,tickpersec : byte;var msecpertick : word);
  246. { This is used to  determine the parameters of the timer tick on any given
  247.   machine.  Applications can use this for critical timing  (granularity of
  248.   less than one second) or to set up code  (such as a watchdog)  that is
  249.   executed on every timer tick. See function 16h (add/delete function from
  250.   timer tick) for the preferred way of actually installing such code.
  251. }
  252.   begin {* TimerInfo *}
  253.     regs.ah := $07;
  254.     Intr($14,regs);
  255.     tickint := regs.al;         { Timer tick interrupt number }
  256.     tickpersec := regs.ah;      { Ticks per second on interrupt number }
  257.     msecpertick := regs.dx      { Approxiamate Milliseconds per Tick }
  258.   end;  {* TimerInfo *}
  259.  
  260. Procedure FLUSHOUTPUT;
  261. { This is used to force any pending output.   It does not return until all
  262.   pending output has been sent.  You should use this call with care.  Flow
  263.   control  (documented below)  can make your system hang on this call in a
  264.   tight uninterruptible loop under the right circumstances.
  265. }
  266.   begin {* FlushOutput *}
  267.     regs.ah := $08;
  268.     regs.dx := fport;
  269.     Intr($14,regs)
  270.   end;  {* FlushOutput *}
  271.  
  272. Procedure PURGEOUTPUT;
  273. { This is used to purge any pending output.   Any output data remaining in
  274.   the output buffer (not transmitted yet) is discarded.
  275. }
  276.   begin {* PurgeOutput *}
  277.     regs.ah := $09;
  278.     regs.dx := fport;
  279.     Intr($14,regs)
  280.   end;  {* PurgeOutput *}
  281.  
  282. Procedure PURGEINPUT;
  283. { This is used to purge any pending input.   Any input data which is still
  284.   in the buffer is discarded.
  285. }
  286.   begin {* PurgeInput *}
  287.     regs.ah := $0A;
  288.     regs.dx := fport;
  289.     Intr($14,regs)
  290.   end;  {* PurgeInput *}
  291.  
  292. Procedure SENDFNOW(fchar : char; var success : boolean);
  293. { This is exactly the same as the "regular"  transmit call, except that if
  294.   the driver is  unable to  buffer the character  (the buffer is full),  a
  295.   value of 0000h is returned in AX. If the driver accepts the character
  296.   (room is available),  0001h is returned in AX.
  297. }
  298.   begin {* SendFNow *}
  299.     regs.ah := $0B;
  300.     regs.al := ord(fchar);
  301.     regs.dx := fport;
  302.     Intr($14,regs);
  303.     success := regs.ax = $0001
  304.   end;  {* SendFNow *}
  305.  
  306. Procedure PEAKFCHAR(fchar : char; var success : boolean);
  307. { Return in AL the next character in the receive buffer.  If the receive
  308.   buffer is empty,  return  FFFFh.  The  character  returned  remains in
  309.   the receive buffer.
  310. }
  311.   begin {* PeakFChar *}
  312.     regs.ah := $0C;
  313.     regs.dx := fport;
  314.     Intr($14,regs);
  315.     if regs.ah = $00 then
  316.       begin
  317.         move(regs.al,fchar,1);
  318.         success := true
  319.       end
  320.     else { regs.ax should equal $FFFF }
  321.       begin
  322.         fchar := char(00);
  323.         success := false
  324.       end
  325.   end;  {* PeakFChar *}
  326.  
  327. Procedure READKNOW(var key : word; var success : boolean);
  328. { Return in  AX the  next character  (non-destructive read ahead)  from the
  329.   keyboard; if nothing is currently in the keyboard buffer, return FFFFh in
  330.   AX.   Use IBM-style  function  key mapping  in the high order byte.  Scan
  331.   codes for non-"function" keys  are not specifically required,  but may be
  332.   included. Function keys return 00h in AL and the "scan code" in AH.
  333. }
  334.   begin {* ReadKNow *}
  335.     regs.ah := $0D;
  336.     Intr($14,regs);
  337.     success := regs.ax <> $FFFF;
  338.     if success then key := regs.ax else key := $0000
  339.   end;  {* ReadKNow *}
  340.  
  341. Procedure READKBD(var key : word);
  342. { Return in AX the next character from the keyboard;  wait if no character
  343.   is available. Keyboard mapping should be the same as function 0Dh.
  344. }
  345.   begin {* ReadKBD *}
  346.     regs.ah := $0E;
  347.     Intr($14,regs);
  348.     key := regs.ax
  349.   end;  {* ReadKBD *}
  350.  
  351. Procedure SETFLOWCONTROL(mask : byte);
  352. { Enable or Disable Flow Control.  See Extended notes after end. of Unit
  353. }
  354.   begin {* SetFlowControl *}
  355.     regs.ah := $0F;
  356.     regs.al := mask;
  357.     regs.dx := fport;
  358.     Intr($14,regs)
  359.   end;  {* SetFlowControl *}
  360.  
  361. Procedure SETCONTCK(mask : byte; var ckstate : boolean);
  362. { mask should be called as a combination of either (ckenable,ckdisable) OR
  363.   (transtop,transclr).  i.e. SetContCK(ckenable or transclr,retstate);
  364.   This is used for BBS  operation,  primarily.  A bit mask is passed in AL
  365.   with the following flags:
  366.               Bit 0   Enable/disable Control-C / Control-K checking
  367.               Bit 1   Disable/enable the transmitter
  368.   The Enable (bit 0 = 1) and Disable (Bit 0 = 0) Control-C/Control-K check
  369.   function is meant primarily for BBS use. When the checking is enabled, a
  370.   Control-C or Control-K received  from the communications port will set a
  371.   flag internal to the FOSSIL driver,  but will not be stored in the input
  372.   buffer. The next use of this function will return the value of this flag
  373.   in register AX then clear the flag for the next occurrence. The returned
  374.   value is used by the BBS  software to determine whether output should be
  375.   halted or not.
  376.   The Disable (Bit 1 = 1) and Enable (Bit 1 = 0) Transmitter function lets
  377.   the application restrain the asynchronous driver from output in much the
  378.   same way as XON/XOFF would.
  379. }
  380.   begin {* SetContCK *}
  381.     regs.ah := $10;
  382.     regs.al := mask;
  383.     regs.dx := fport;
  384.     Intr($14,regs);
  385.     ckstate := regs.ax = $0001  { Ctrl-C/Ctrl-K has been recieved }
  386.   end;  {* SetContCK *}
  387.  
  388. Procedure SETCURSOR(row,column : byte);
  389. { This function looks exactly like INT 10h, subfuction 2, on the IBM PC.
  390.   The cursor location is passed in DX: row in DH and column in DL. The
  391.   function treats the screen as a coordinate  system whose origin (0,0) is
  392.   the upper left hand corner of the screen.
  393. }
  394.   begin {* SetCursor *}
  395.     regs.ah := $11;
  396.     regs.dh := row;
  397.     regs.dl := column;
  398.     Intr($14,regs)
  399.   end;  {* SetCursor *}
  400.  
  401. Procedure GETCURSOR(var row,column : byte);
  402. { Looks exactly like INT 10h,  subfunction 3,  on the IBM PC.  The current
  403.   cursor location  (using the same coordinate  system as  function 16h) is
  404.   passed back in DX.
  405. }
  406.   begin {* GetCursor *}
  407.     regs.ah := $12;
  408.     Intr($14,regs);
  409.     row := regs.dh;
  410.     column := regs.dl
  411.   end;  {* GetCursor *}
  412.  
  413. Procedure ANSICHAR(fchar : char);
  414. { The character in AL is sent to the screen by the fastest method possible
  415.   that allows ANSI processing to occur (if available). This routine should
  416.   not be used in such a way that DOS output  (which is not re-entrant) can
  417.   not be employed by some FOSSIL driver to perform the function  (in fact,
  418.   on the IBM PC that is likely to be how it's done).
  419. }
  420.   begin
  421.     regs.ah := $13;
  422.     regs.al := ord(fchar);
  423.     Intr($14,regs)
  424.   end;
  425.  
  426. Procedure SETWATCHDOG(enable : boolean);
  427. { When watchdog is enabled,   the state of the carrier detect (CD) line on
  428.   the comm port specified in DX should be constantly monitored. Should the
  429.   state of that line become FALSE (carrier lost), the system should be re-
  430.   booted, to enable the BBS (or other application) to start up again. This
  431.   monitor is not affected by Init/Uninit etc.
  432. }
  433.   begin {* SetWatchDog *}
  434.     regs.ah := $14;
  435.     if enable then regs.al := $01 else regs.al := $00;
  436.     regs.dx := fport;
  437.     Intr($14,regs)
  438.   end;  {* SetWatchDog *}
  439.  
  440. Procedure BIOSCHAR(fchar : char);
  441. { The character in AL is sent to the screen using  BIOS-level Input/Output
  442.   routines. This differs from function 13h in that DOS I/O CAN NOT be used,
  443.   as this function might be called from driver level.
  444. }
  445.   begin {* BIOSChar *}
  446.     regs.ah := $15;
  447.     regs.al := ord(fchar);
  448.     Intr($14,regs)
  449.   end;  {* BIOSChar *}
  450.  
  451. Procedure SETTICKFUNC(faddr : pointer;putin : boolean;var success : boolean);
  452. { This function is used to allow a  central authority  to manage the timer
  453.   interrupts, so that as code is loaded and unloaded, the integrity of the
  454.   "chain" is not compromised.  Rather than using the traditional method of
  455.   saving the old contents of the timer vector, storing the address of your
  456.   routine there,  and executing a far call to the "old" routine when yours
  457.   is done, instead you call this function. It manages a list of such entry
  458.   points and calls them on a timer tick (interrupt) using a FAR call.  All
  459.   the usual cautions about making DOS calls apply (that is, DON'T!).
  460.   This makes it possible for a program to get in and out of the tick chain
  461.   without having to know whether another program has also done so since it
  462.   first insinuated itself.   At least 4 entries should be available in the
  463.   driver's table (including one to be used by Watchdog if implemented that
  464.   way).
  465. }
  466.   var
  467.     tickfunc : ptrmask absolute faddr;
  468.  
  469.   begin {* SetTickFunc *}
  470.     regs.ah := $16;
  471.     if putin then regs.al := $01 else regs.al := $00;
  472.     regs.es := tickfunc.pseg;    { Segment of function }
  473.     regs.dx := tickfunc.poff;    { Offset of function }
  474.     Intr($14,regs);
  475.     success := regs.ax = $0000
  476.   end;  {* SetTickFunc *}
  477.  
  478. Procedure COLDBOOT;
  479. { Used in extreme emergency by code that can't seem to find a "clean" way
  480.   out of the trouble it has gotten itself into.  Hopefully it won't happen
  481.   while you're computing something in the other half of a DoubleDOS system.
  482.   A "cold" boot is contains a  power-up, self-test and boot, a "warm" boot
  483.   just re-boots the computer.
  484. }
  485.   begin {* ColdBoot *}
  486.     regs.ah := $17;
  487.     regs.al := $00;
  488.     Intr($14,regs)
  489.   end;  {* ColdBoot *}
  490.  
  491. Procedure WARMBOOT;
  492. { See definition in Procedure ColdBoot
  493. }
  494.   begin {* WarmBoot *}
  495.     regs.ah := $17;
  496.     regs.al := $01;
  497.     Intr($14,regs)
  498.   end;  {* WarmBoot *}
  499.  
  500. Procedure READFBLOCK(buffaddr : pointer;numtoread : word;var numread : word);
  501. { A "no-wait"  block read of 0 to FFFFh characters from the FOSSIL inbound
  502.   ring buffer to the calling routine's buffer. ES:DI are left unchanged by
  503.   the call; the count of bytes actually transferred will be returned in AX.
  504. }
  505.   var
  506.     buffer : ptrmask absolute buffaddr;
  507.  
  508.   begin {* ReadFBlock *}
  509.     regs.ah := $18;
  510.     regs.cx := numtoread;
  511.     regs.dx := fport;
  512.     regs.es := buffer.pseg;
  513.     regs.di := buffer.poff;
  514.     Intr($14,regs);
  515.     numread := regs.ax
  516.   end;  {* ReadFBlock *}
  517.  
  518. Procedure WRITEFBLOCK(buffaddr : pointer;numtosend : word;var numsent : word);
  519. { A  "no-wait"  block  move of 0  to FFFFh  characters  from  the  calling
  520.   program's  buffer into  the  FOSSIL outbound ring buffer. ES:DI are left
  521.   unchanged by the call;  the count of bytes actually transferred  will be
  522.   returned in AX.
  523. }
  524.   var
  525.     buffer : ptrmask absolute buffaddr;
  526.  
  527.   begin {* WriteFBlock *}
  528.     regs.ah := $19;
  529.     regs.cx := numtosend;
  530.     regs.dx := fport;
  531.     regs.es := buffer.pseg;
  532.     regs.di := buffer.poff;
  533.     Intr($14,regs);
  534.     numsent := regs.ax
  535.   end;  {* WriteFBlock *}
  536.  
  537. Procedure SETBREAKSIGNAL(startbreak : boolean);
  538. { Send a break signal to the modem. If AL=01h the driver will commence the
  539.   transmission of a break.  If AL=00h the driver will end the break.  This
  540.   is useful for communications with devices that can only go into 'command
  541.   mode' when a BREAK is received. Note: the application is responsible for
  542.   the timing of the BREAK.  Also,  if the FOSSIL has been restrained by an
  543.   Xoff received from the modem, the flag will be cleared.   An Init or Un-
  544.   Init will stop an in-progress BREAK.
  545. }
  546.   begin {* SetBreakSignal *}
  547.     regs.ah := $1A;
  548.     if startbreak then regs.al := $01 else regs.al := $00;
  549.     regs.dx := fport;
  550.     Intr($14,regs)
  551.   end;  {* SetBreakSignal *}
  552.  
  553. Procedure DRIVERINFO(buffaddr : pointer; numtoread : word;var numread : word);
  554. { Transfer information about the driver and its current status to the user
  555.   for use in determining,  at the application level, limits of the driver.
  556.   Designed to assist  "generic" applications  to adjust to "foreign" gear.
  557.   the Type fossinforec has been added (but untested) for your convenience.
  558.   The ident string should be  null-terminated,  and NOT contain a newline.
  559.   The baud rate byte contains the bits that  Function 00h would use to set
  560.   the port to that speed.
  561.   The fields related to a particular port (buffer size,  space left in the
  562.   buffer,  baud rate) will be undefined if port FFh  or an invalid port is
  563.   contained in DX.
  564.   Additional information will always be passed after these,  so that,  for
  565.   example, offset "sheight" will never change with FOSSIL revision changes.
  566. }
  567.   var
  568.     infobuff : ptrmask absolute buffaddr;
  569.  
  570.   begin {* DriverInfo *}
  571.     regs.ah := $1B;
  572.     regs.cx := numtoread;
  573.     regs.dx := fport;
  574.     regs.es := infobuff.pseg;
  575.     regs.di := infobuff.poff;
  576.     Intr($14,regs);
  577.     numread := regs.ax
  578.   end;  {* DriverInfo *}
  579.  
  580. Function FCARRIER : boolean;
  581. { AL Bit 7 = DCD  - carrier detect }
  582.   begin {*f FCarrier *}
  583.     GetFStatus;
  584.     FCarrier := lo(fresult) and $80 = $80
  585.   end;  {* fFCarrier *}
  586.  
  587. Function INPUTREADY : boolean;
  588. { AH Bit 0 = RDA  - input data is available in buffer }
  589.   begin { fInputReady *}
  590.     GetFStatus;
  591.     InputReady := hi(fresult) and $01 = $01
  592.   end;  {* fInputReady *}
  593.  
  594. Function OUTPUTREADY : boolean;
  595. { AH Bit 5 = THRE - room is available in output buffer }
  596.   begin {* fOutputReady *}
  597.     GetFStatus;
  598.     OutputReady := hi(fresult) and $20 = $20
  599.   end;  {* fOutputReady *}
  600.  
  601. end.  Unit
  602.  
  603. The following is more in depth documentation regarding the following
  604. procedures.  They are not used by the BBS Onliner Interface, and are
  605. included only for completeness.  To implement these procedures in other
  606. programs, you will probably want to implement certain predeclared constants
  607. to allow for easier coding of the 'mask' variables.
  608.  
  609. Procedure SETBAUDRATE(mask : byte);
  610. Procedure SETFLOWCONTROL(mask : byte);
  611.  
  612. SetBaudRate
  613.     AH = 00h    Set baud rate
  614.             Parameters:
  615.                 Entry:  AL = Baud rate code
  616.                         DX = Port number
  617.                 Exit:   AX = Port status (see function 03h)
  618.     This works the same as the  equivalent IBM PC BIOS call,  except that it
  619.     ONLY selects a baud rate.  This is passed in the high order 3 bits of AL
  620.     as follows:
  621.                 010 =   300 baud
  622.                 011 =   600  ''
  623.                 100 =  1200  ''
  624.                 101 =  2400  ''
  625.                 110 =  4800  ''
  626.                 111 =  9600  ''
  627.                 000 = 19200  '' (Replaces old 110 baud mask)
  628.                 001 = 38400  '' (Replaces old 150 baud mask)
  629.     The low order 5 bits can be implemented or not by the FOSSIL, but in all
  630.     cases, if the low order bits of AL are 00011,  the result should be that
  631.     the communications device should be set to eight data bits, one stop bit
  632.     and no parity. This setting is a  MINIMUM REQUIREMENT  of Fido, Opus and
  633.     SEAdog.  For purposes of completeness,  here are the IBM PC "compatible"
  634.     bit settings:
  635.     Bits 4-3 define parity:     0 0       no parity
  636.                                 1 0       no parity
  637.                                 0 1      odd parity
  638.                                 1 1     even parity
  639.     Bit 2 defines stop bits:      0        1 stop bit;
  640.                                   1      1.5 bits for 5-bit char;
  641.                                            2 for others
  642.     Bits 1-0 character length:  0 0        5 bits
  643.                                 0 1        6 bits
  644.                                 1 0        7 bits
  645.                                 1 1        8 bits
  646.  
  647. SetFlowControl
  648.     AH = 0Fh    Enable or disable flow control
  649.             Parameters:
  650.                 Entry:  AL = Bit mask describing requested flow control
  651.                         DX = Port number
  652.                 Exit:   None
  653.  
  654.     TRANSMIT flow control allows the "other end" to restrain the transmitter
  655.     when you are  over-running it.  RECEIVE flow control tells the FOSSIL to
  656.     attempt to do just that if it is being overwhelmed.
  657.  
  658.     Two kinds of basic flow control are supported:
  659.                 Bit 0 = 1       Xon/Xoff on transmit
  660.                 Bit 1 = 1       CTS/RTS (CTS on transmit, RTS on receive)
  661.                 Bit 2           Reserved
  662.                 Bit 3 = 1       Xon/Xoff on Receive
  663.  
  664.     Flow control is enabled, or disabled, by setting the appropriate bits in
  665.     AL  for the types of flow control we want to ENABLE (value = 1),  and/or
  666.     DISABLE  (value = 0),  and calling this function.  Bit 2 is reserved for
  667.     DSR/DTR,  but is not currently supported in any implementation.
  668.     Enabling  transmit  Xon/Xoff will cause the FOSSIL  to stop transmitting
  669.     upon receiving an Xoff.  The FOSSIL will resume transmitting when an Xon
  670.     is received.
  671.     Enabling CTS/RTS will cause the FOSSIL to cease transmitting when CTS is
  672.     lowered.  Transmission will resume  when CTS is raised.  The FOSSIL will
  673.     drop RTS when the receive buffer reaches a predetermined percentage full
  674.     The FOSSIL will  raise RTS  when the  receive buffer  empties below  the
  675.     predetermined  percentage full.  The  point(s)  at which  this occurs is
  676.     left to the individual FOSSIL implementor.
  677.     Enabling receive  Xon/Xoff will cause the FOSSIL to send a Xoff when the
  678.     receive buffer reaches a pre-determined percentage full.  An Xon will be
  679.     sent when the receive buffer empties below the pre-determined percentage
  680.     full. The point(s) at which this occurs is left to the individual FOSSIL
  681.     implementor.
  682.     Applications  using this  function  should set all bits  ON  in the high
  683.     nibble of AL as well.  There is a compatible  (but not identical) FOSSIL
  684.     driver implementation that uses the  high nibble as a control mask.   If
  685.     your application sets the high nibble to all ones,  it will always work,
  686.     regardless of the method used by any given driver.
  687.  
  688.